


#ifndef BIGNUMBER_H
#define BIGNUMBER_H

#include <vector>
#include <string>
#include <iostream>

/**
 * BigInteger class
 */
class BigInteger {
public:
    
    /**
     * BigInteger constructor
     * @param number - The initial value of the BigInteger
     */
    BigInteger(std::string number);
    BigInteger(long long number);
    

    /**
     * Add anaNumber BigInteger to the current instance
     * @param aNumber - The aNumber BigInteger
     * @return The sum of the two BigNumbers
     */
    BigInteger add(BigInteger aNumber);

    /**
     * Subtract anaNumber BigInteger from the current instance
     * @param aNumber - The aNumber BigInteger
     * @return The difference of the two BigNumbers
     */
    BigInteger subtract(BigInteger aNumber);
    BigInteger mod(BigInteger aNumber);
    BigInteger operator % (BigInteger b);
    BigInteger modPow(BigInteger a,BigInteger b);
    /**
     * Multiply the current instance by anaNumber BigInteger
     * @param aNumber - The aNumber BigInteger
     * @return The product of the two BigNumbers
     */
    BigInteger multiply(BigInteger aNumber);
    
    /**
     * Divide the current instance by anaNumber BigInteger
     * @param aNumber - The aNumber BigInteger
     * @return The quotient of the two BigNumbers
     */
    BigInteger divide(BigInteger aNumber);

    /**
     * Raise the current instance to the power of an exponent
     * @param exponent - The power to be raised by
     * @return - The resulting BigInteger after exponentiation
     */
    BigInteger pow(int exponent);
    BigInteger();
    virtual ~BigInteger();
    /**
     * Get the string value of the current instance
     * @return The BigInteger as a string
     */
    std::string getString();
    std::string getNumber();

    /**
     * Set the value of the current instance with a string
     * @param newStr - The new value for the BigInteger
     * @return The BigInteger with the new value
     */
    BigInteger setString(const std::string &newStr);

    /**
     * Negates the current instance
     * @return The BigInteger after negation
     */
    BigInteger negate();
    
    BigInteger trimLeadingZeros();

    
    /**
     * Check if anaNumber BigInteger is equal to the current instance
     * @param aNumber - The aNumber BigInteger
     * @return True if equal, aNumberwise false
     */
    bool equals(const BigInteger &aNumber);
    bool equals(const long long &aNumber);
    bool equals(const std::string &aNumber);
    

    /**
     * Get the number of digits in the current instance
     * @return The number of digits
     */
    unsigned int digits();

    /**
     * Get whether or not the current instance is a negative number
     * @return True if negative, aNumberwise false
     */
    bool isNegative() const;

    /**
     * Get whether or not the current instance is a positive number
     * @return True if positive, aNumberwise false
     */
    bool isPositive();

    /**
     * Get whether or not the current instance is an even number
     * @return True if even, aNumberwise false
     */
    bool isEven();

    /**
     * Get whether or not the current instance is an odd number
     * @return True if odd, aNumberwise false
     */
    bool isOdd();

    /**
     * Get the absolute value of the current instance
     * @return The absolute value of the BigInteger
     */
    BigInteger abs() const;
    
    /**
     * Output stream operator
     * @param os The output stream
     * @param num The current instance
     * @return The output stream with the current instance
     */
    friend std::ostream &operator<<(std::ostream &os, const BigInteger &num);
    
    
    /**
     * Addition operator
     * @param b1 - The current instance
     * @param b2 - The number being added
     * @return The sum of the two numbers
     */
    friend BigInteger operator+(BigInteger b1, const BigInteger &b2);
    friend BigInteger operator+(BigInteger b1, const long long &b2);
    friend BigInteger operator+(BigInteger b1, const std::string &b2);
    
    
    
    /**
     * Subtraction operator
     * @param b1 - The current instance
     * @param b2 - The number being subtracted
     * @return The difference of the two numbers
     */
    friend BigInteger operator-(BigInteger b1, const BigInteger &b2);
    friend BigInteger operator-(BigInteger b1, const long long &b2);
    friend BigInteger operator-(BigInteger b1, const std::string &b2);
    
    
    
    /**
     * Multiplication operator
     * @param b1 - The current instance
     * @param b2 - The number being multiplied by
     * @return The product of the two numbers
     */
    friend BigInteger operator*(BigInteger b1, const BigInteger &b2);
    friend BigInteger operator*(BigInteger b1, const long long &b2);
    friend BigInteger operator*(BigInteger b1, const std::string &b2);
    
    
    
    /**
     * Division operator
     * @param b1 - The current instance
     * @param b2 - The number being divided by
     * @return The quotient of the two numbers
     */
    friend BigInteger operator/(BigInteger b1, const BigInteger &b2);
    friend BigInteger operator/(BigInteger b1, const long long &b2);
    friend BigInteger operator/(BigInteger b1, const std::string &b2);
    
    
    /**
     * Exponent operator
     * @param b1 - The current instance
     * @param b2 - The exponent
     * @return The value after exponentiation
     */
    friend BigInteger operator^(BigInteger b1, const int &b2);
    
    
    /**
     * Equality operator
     * @param b1 - The current instance
     * @param b2 - AnaNumber value
     * @return True if equal, aNumberwise false
     */
    friend bool operator==(BigInteger b1, const BigInteger &b2);
    friend bool operator==(BigInteger b1, const long long &b2);
    friend bool operator==(BigInteger b1, const std::string &b2);
    
    
    /**
     * Greater-than operator
     * @param b1 - The current instance
     * @param b2 - AnaNumber BigInteger
     * @return True if current instance is greater, aNumberwise false
     */
    friend bool operator>(BigInteger b1, const BigInteger &b2);
    
    /**
     * Less-than operator
     * @param b1 - The current instance
     * @param b2 - AnaNumber BigInteger
     * @return True if current instance is less, aNumberwise false
     */
    friend bool operator<(BigInteger b1, const BigInteger &b2);
    bool operator & (int a);

    int theLastDigit(std::string s);
    /**
     * Greater-than or equal-to operator
     * @param b1 - The current instance
     * @param b2 - AnaNumber BigInteger
     * @return True if current instance is greater or equal, aNumberwise false
     */
    friend bool operator>=(BigInteger b1, const BigInteger &b2);
    
    /**
     * Less-than or equal-to operator
     * @param b1 - The current instance
     * @param b2 - AnaNumber BigInteger
     * @return True if current instance is less or equal, aNumberwise false
     */
    friend bool operator<=(BigInteger b1, const BigInteger &b2);

    
    /**
     * Assignment operator
     * @param aNumber - The new value for the BigInteger
     * @return A BigInteger containing the new value
     */
    BigInteger& operator=(const BigInteger &aNumber);
    BigInteger& operator=(const long long &aNumber);
    BigInteger& operator=(const std::string &aNumber);
    
    
    
    /**
     * Addition assignment operator\n
     * Adds and assigns a value to the current instance
     * @param aNumber - The value being added
     * @return The new value after addition and assignment
     */
    BigInteger& operator+=(const BigInteger &aNumber);
    BigInteger& operator+=(const long long &aNumber);
    BigInteger& operator+=(const std::string &aNumber);
    
    
    
    /**
     * Subtraction assignment operator\n
     * Subtracts and assigns a value to the current instance
     * @param aNumber - The value being subtracted
     * @return The new value after subtraction and assignment
     */
    BigInteger& operator-=(const BigInteger &aNumber);
    BigInteger& operator-=(const long long &aNumber);
    BigInteger& operator-=(const std::string &aNumber);
    
    
    
    /**
     * Multiplication assignment operator\n
     * Multiplies and assigns a value to the current instance
     * @param aNumber - The value being multiplied
     * @return The new value after multiplication and assignment
     */
    BigInteger& operator*=(const BigInteger &aNumber);
    BigInteger& operator*=(const long long &aNumber);
    BigInteger& operator*=(const std::string &aNumber);
    
    
    
    /**
     * Division assignment operator\n
     * Divides and assigns a value to the current instance
     * @param aNumber - The value being divided
     * @return The new value after division and assignment
     */
    BigInteger& operator/=(const BigInteger &aNumber);
    BigInteger& operator/=(const long long &aNumber);
    BigInteger& operator/=(const std::string &aNumber);
    

    /**
     * Pre-increment operator
     * @return The incremented BigInteger
     */
    BigInteger& operator++();
    
    /**
     * Pre-decrement operator
     * @return The decremented BigInteger
     */
    BigInteger& operator--();
    
    /**
     * Post-increment operator
     * @return The incremented BigInteger
     */
    BigInteger operator++(int);
    
    /**
     * Post-decrement operator
     * @return The decremented BigInteger
     */
    BigInteger operator--(int);

    /**
     * The index operator
     * @param index The position being looked at
     * @return The number at the specified position in the BigInteger string
     */
    unsigned int operator[](int index);
    std::string _numberString;
private:
          
    
    
    BigInteger addll(const long long &aNumber);
    BigInteger addstr(const std::string &aNumber);
    BigInteger subtractll(const long long &aNumber);
    BigInteger subtractstr(const std::string  &aNumber);
    BigInteger multiplyll(const long long &aNumber);
    BigInteger multiplystr(const std::string &aNumber);
    BigInteger dividell(const long long &aNumber);
    BigInteger dividestr(const std::string &aNumber);
};



#endif